package framework.dao.jdbc.template;

import framework.dao.exception.DataAccessException;
import framework.dao.jdbc.callback.ConnectionCallback;
import framework.dao.jdbc.callback.ResultSetExtractor;
import framework.dao.jdbc.callback.RowMapper;
import framework.dao.jdbc.util.JdbcUtil;

import java.sql.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class JdbcTemplate {

    public <T> List<T> query(String sql, Object[] args, RowMapper<T> rowMapper){
        Connection con=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        List<T> list=new ArrayList<T>();
        try {
            con=JdbcUtil.getConnection();

            ps=con.prepareStatement(sql);

            for (int i = 0; i < args.length; i++) {
                setParam(i+1,args[i],ps);
            }

            rs=ps.executeQuery();

            while(rs.next()){
                T t=rowMapper.mapRow(rs);
                list.add(t);
            }


        } catch (Exception e){
            e.printStackTrace();
            throw new DataAccessException("数据访问失败",e);
        } finally {
            JdbcUtil.close(null,ps,rs);
        }

        return list;
    }

    public <T> T query(String sql, ResultSetExtractor<T> rse, Object... args){
        Connection con=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        T t=null;
        try {
            con=JdbcUtil.getConnection();

            ps=con.prepareStatement(sql);

            for (int i = 0; i < args.length; i++) {
                setParam(i+1,args[i],ps);
            }

            rs=ps.executeQuery();

            t=rse.extractData(rs);


        } catch (Exception e){
            e.printStackTrace();
            throw new DataAccessException("数据访问失败",e);
        } finally {
            JdbcUtil.close(null,ps,rs);
        }

        return t;
    }



    public <T> T execute(ConnectionCallback<T> action){
        Connection con=null;
        PreparedStatement ps=null;
        T t=null;
        try {
            con=JdbcUtil.getConnection();

            t=action.doInConnection(con);


        } catch (Exception e){
            e.printStackTrace();
            throw new DataAccessException("数据访问失败",e);
        } finally {
            JdbcUtil.close(null,ps,null);
        }

        return t;
    }



    public void update(String sql,Object... args){
        Connection con=null;
        PreparedStatement ps=null;
        try {
            con=JdbcUtil.getConnection();

            ps=con.prepareStatement(sql);

            for (int i = 0; i < args.length; i++) {
                setParam(i+1,args[i],ps);
            }

            ps.executeUpdate();

        } catch (Exception e){
            e.printStackTrace();
            throw new DataAccessException("数据访问失败",e);
        } finally {
            JdbcUtil.close(null,ps,null);
        }

    }


    public Integer save(String sql,Object... args){
        Connection con=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        Integer id=null;
        try {
            con=JdbcUtil.getConnection();

            ps=con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);

            for (int i = 0; i < args.length; i++) {
                setParam(i+1,args[i],ps);
            }

            ps.executeUpdate();

            rs=ps.getGeneratedKeys();

            if(rs.next()){
                id=rs.getInt(1);
            }


        } catch (Exception e){
            e.printStackTrace();
            throw new DataAccessException("数据访问失败",e);
        } finally {
            JdbcUtil.close(null,ps,rs);
        }
        return id;

    }
    public Integer save(String sql,String idCloumnName,Object... args){
        Connection con=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        Integer id=null;
        try {
            con=JdbcUtil.getConnection();

            ps=con.prepareStatement(sql, new String[]{idCloumnName});

            for (int i = 0; i < args.length; i++) {
                setParam(i+1,args[i],ps);
            }

            ps.executeUpdate();

            rs=ps.getGeneratedKeys();

            if(rs.next()){
                id=rs.getInt(1);
            }

        } catch (Exception e){
            e.printStackTrace();
            throw new DataAccessException("数据访问失败",e);
        } finally {
            JdbcUtil.close(null,ps,rs);
        }
        return id;
    }

    public Integer save(String sql,int idCloumnIndex,Object... args){
        Connection con=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        Integer id=null;
        try {
            con=JdbcUtil.getConnection();

            ps=con.prepareStatement(sql, new int[]{idCloumnIndex});

            for (int i = 0; i < args.length; i++) {
                setParam(i+1,args[i],ps);
            }

            ps.executeUpdate();

            rs=ps.getGeneratedKeys();

            if(rs.next()){
                id=rs.getInt(1);
            }

        } catch (Exception e){
            e.printStackTrace();
            throw new DataAccessException("数据访问失败",e);
        } finally {
            JdbcUtil.close(null,ps,rs);
        }
        return id;
    }




    private void setParam(int index,Object param,PreparedStatement ps) throws Exception {
        if(param==null){
            ps.setNull(index, Types.VARCHAR);
        }else if(param instanceof String){
            ps.setString(index, (String) param);
        }else if(param instanceof Integer||param.getClass().equals(int.class)){
            ps.setInt(index, (Integer) param);
        }else if(param instanceof Long||param.getClass().equals(long.class)){
            ps.setLong(index, (Long) param);
        }else if(param instanceof Double||param.getClass().equals(double.class)){
            ps.setDouble(index, (Double) param);
        }else if(param instanceof Boolean||param.getClass().equals(boolean.class)){
            ps.setBoolean(index, (Boolean) param);
        }else if(param instanceof java.sql.Date){
            ps.setDate(index, (java.sql.Date) param);
        }else if(param instanceof java.sql.Time){
            ps.setTime(index, (java.sql.Time) param);
        }else if(param instanceof java.sql.Timestamp){
            ps.setTimestamp(index, (java.sql.Timestamp) param);
        }else if(param instanceof Date){
            ps.setTimestamp(index, new java.sql.Timestamp(((Date)param).getTime()));
        }else{
            ps.setObject(index,param);
        }
    }


}
